package dao

import (
	"context"
	"errors"
	"github.com/go-sql-driver/mysql"
	"gorm.io/gorm"
	"time"
)

// 异常定义
var (
	ErrDuplicatedEmail        = errors.New("邮箱已被占用,请修改后重试")
	ErrRecordNotFound = gorm.ErrRecordNotFound
)

// UserDAO 用户数据库操作
type UserDAO struct {
	db *gorm.DB //组合gorm
}

func NewUserDao(db *gorm.DB) *UserDAO {
	return &UserDAO{
		db: db,
	}
}

func (dao *UserDAO) Insert(ctx context.Context, user *User) error {
	err := dao.db.WithContext(ctx).Create(&user).Error

	//校验MySQL异常
	var mse *mysql.MySQLError
	if errors.As(err, &mse) { //Type Assertion 类型断言
		//判断是否为唯一索引异常
		const ukErrNo uint16 = 1062
		if ukErrNo == mse.Number {
			return ErrDuplicatedEmail
		}
	}

	return err
}

// SelectByEmail 根据邮箱查询用户
func (dao *UserDAO) SelectByEmail(ctx context.Context, email string) (*User, error) {
	var u User
	err := dao.db.WithContext(ctx).Where(" email = ? ", email).First(&u).Error
	if errors.Is(err, gorm.ErrRecordNotFound) { //未查找到用户,返回通用异常
		return &User{}, ErrRecordNotFound
	}
	return &u, err
}

// SelectById 根据主键ID查询用户
func (dao *UserDAO) SelectById(ctx context.Context, uid int64) (*User, error) {
	var u User
	err := dao.db.WithContext(ctx).First(&u, uid).Error
	if errors.Is(err, gorm.ErrRecordNotFound) { //未查找到用户,返回通用异常
		return &User{}, ErrRecordNotFound
	}
	return &u, err
}

// UpdateNonZeroField 更新非零值字段
func (dao *UserDAO) UpdateNonZeroField(ctx context.Context, user *User) error {
	utime := time.Now().UnixMilli()
	user.Utime = utime
	//使用ID作为where条件,并仅更新非零值字段
	return dao.db.WithContext(ctx).Updates(&user).Error
}

// User 数据库模型,
// domain.User是业务模型,不一定与数据库表结构一一对应,因此在dao中单独定义数据模型,直接映射数据库表记录
type User struct {
	Id       int64  `gorm:"primaryKey,autoIncrement"` //自增主键
	Email    string `gorm:"unique"`                   //邮箱,唯一索引
	Password string //密码
	Nickname string //昵称
	Birthday string //生日
	AboutMe  string //个人简介
	Avatar   string //头像
	Ctime    int64  `gorm:"autoCreateTime:milli"` //创建时间戳(ms)	数据中尽量不要使用有格式的日期或时间,因为存在时区问题
	Utime    int64  `gorm:"autoUpdateTime:milli"` //更新时间戳(ms)	使用gorm自动的autoCreateTime和autoUpdateTime
}
